"""API routes for the CLU service."""

from fastapi import APIRouter
from typing import List, Dict, Any, Optional
import asyncio
from datetime import datetime, timezone, timedelta

# 东八区时区常量
CHINA_TZ = timezone(timedelta(hours=8))

from models import (
    ProjectResponse,
    TrainingConfig,
    DeploymentConfig,
    ConversationRequest,
    IntentResponse,
    ExportResultRequest,
    BatchConversationRequest,
    BatchConversationResponse,
    CheckedApplicationsRequest,
    CosmosDBQueryRequest,
    DefaultConversationRequest,
    IntentQueryRequest,
    IntentQueryResponse,
)
from services import (
    ProjectService,
    TrainingService,
    DeploymentService,
    ConversationService,
    IntentService,
    UtilsService,
    LogsService
)
from exceptions import (
    CLUServiceError,
    CosmosDBConnectionError,
    CosmosDBConfigurationError,
    CosmosDBError,
    CosmosDBQueryError,
    DeploymentError,
    EmptyMessageError,
    InvalidRequestBodyError,
    MissingParameterError,
    InvalidConfigError
)


# Initialize services
project_service = ProjectService()
training_service = TrainingService()
deployment_service = DeploymentService()
intent_service = IntentService()
utils_service = UtilsService()
logs_service = LogsService()
conversation_service = ConversationService(utils_service)



# Create routers
project_router = APIRouter(prefix="/project", tags=["Project Management"])
clu_router = APIRouter(prefix="/api/clu", tags=["CLU Operations"])
utils_router = APIRouter(prefix="/api/utils", tags=["Utils Operations"])
health_router = APIRouter(tags=["Health Check"])
logs_router = APIRouter(prefix="/api/logs", tags=["Logs Management"])

# --- Health Check ---
@health_router.get("/health")
async def health_check():
    """健康检查端点，返回服务状态。"""
    # 使用东八区时区
    return {
        "status": "healthy",
        "service": "CLU API Service",
        "timestamp": datetime.now(CHINA_TZ).isoformat()
    }

@health_router.get("/config")
async def get_config_info():
    """获取配置信息，从CosmosDB显示应用程序列表（包含checked状态和最新部署信息）和置信度阈值。"""
    from config import settings
    
    # 获取置信度阈值
    confidence_threshold = await conversation_service._get_confidence_threshold()
    
    # 从CosmosDB获取所有应用程序（不筛选checked状态）
    try:
        # 获取所有应用程序（checked=None表示不筛选）
        all_apps_request = CheckedApplicationsRequest(checked=None)
        all_apps_response = await utils_service.get_checked_applications(all_apps_request)
        
        if not all_apps_response.application_names:
            # 如果CosmosDB中没有应用程序配置
            return {
                "endpoint": settings.endpoint[:50] + "..." if len(settings.endpoint) > 50 else settings.endpoint,
                "applications": [],
                "applications_count": 0,
                "checked_applications_count": 0,
                "host": settings.host,
                "port": settings.port,
                "default_language": settings.default_language,
                "log_level": settings.log_level,
                "confidence_threshold": confidence_threshold,
                "data_source": "CosmosDB"
            }
        
        # 重新查询CosmosDB获取完整的应用程序信息（包含checked状态）
        cosmos_request = CosmosDBQueryRequest(target_key="System.LUIS.CheckedApplications")
        cosmos_response = await utils_service.query_cosmos_setting(cosmos_request)
        
        applications_with_deployment = []
        checked_count = 0
        
        if cosmos_response.found and cosmos_response.value:
            applications_data = cosmos_response.value
            
            # 为每个应用程序获取最新部署信息
            for app_data in applications_data:
                if not isinstance(app_data, dict) or 'applicationName' not in app_data:
                    continue
                
                app_name = app_data['applicationName']
                is_checked = app_data.get('checked', False)
                
                if is_checked:
                    checked_count += 1
                
                # 获取最新部署信息
                deployment_name = ""
                latest_deployment_training_time = ""
                
                try:
                    from types import SimpleNamespace
                    target = SimpleNamespace(projectName=app_name, deploymentName="")
                    deployment_info = await deployment_service.get_latest_deployment_info(target, include_training_time=True)
                    
                    if deployment_info.get("status") == "success":
                        deployment_name = deployment_info.get("deploymentName", "")
                        latest_deployment_training_time = deployment_info.get("latestDeploymentTrainingTime", "")
                    
                except Exception:
                    # 如果获取部署信息失败，使用空值
                    pass
                
                app_info = {
                    "applicationName": app_name,
                    "checked": is_checked,
                    "deploymentName": deployment_name,
                    "latestDeploymentTrainingTime": latest_deployment_training_time
                }
                
                applications_with_deployment.append(app_info)
        
        return {
            "endpoint": settings.endpoint[:50] + "..." if len(settings.endpoint) > 50 else settings.endpoint,
            "applications": applications_with_deployment,
            "applications_count": len(applications_with_deployment),
            "checked_applications_count": checked_count,
            "host": settings.host,
            "port": settings.port,
            "default_language": settings.default_language,
            "log_level": settings.log_level,
            "confidence_threshold": confidence_threshold,
            "data_source": "CosmosDB"
        }
        
    except Exception as e:
        # 如果CosmosDB查询失败，返回基本配置信息
        return {
            "endpoint": settings.endpoint[:50] + "..." if len(settings.endpoint) > 50 else settings.endpoint,
            "applications": [],
            "applications_count": 0,
            "checked_applications_count": 0,
            "host": settings.host,
            "port": settings.port,
            "default_language": settings.default_language,
            "log_level": settings.log_level,
            "confidence_threshold": confidence_threshold,
            "data_source": "CosmosDB",
            "error": str(e)
        }
    

# --- Project Resource ---
@project_router.get("/", response_model=List[ProjectResponse])
async def list_projects(include_deployment_info: bool = False):
    """
    Get all projects.
    
    Args:
        include_deployment_info: If True, includes the latest deployment info for each project. Defaults to False.
    """
    return await project_service.list_projects(include_deployment_info=include_deployment_info)

@project_router.get("/{project_name}", response_model=ProjectResponse)
async def get_project(project_name: str):
    """Get project details."""
    return await project_service.get_project(project_name)

@project_router.delete("/{project_name}")
async def delete_project(project_name: str):
    """Delete a project."""
    return await project_service.delete_project(project_name)

@project_router.post("/{project_name}/import")
async def import_project(project_name: str, project: Dict[str, Any]):
    """Triggers a job to import a project. If a project with the same name already exists, the data of that project is replaced."""
    return await project_service.import_project(project_name, project)

@project_router.get("/{project_name}/import/{job_id}")
async def get_import_project(project_name: str, job_id: str):
    """Get status of an import operation."""
    project = await project_service.get_import_project_job_status(project_name, job_id)
    return project.result()

@project_router.post("/{project_name}/export")
async def export_project(project_name: str, asset_kind:str):
    """Export a project."""
    return await project_service.export_project(project_name)

@project_router.get("/{project_name}/export/{job_id}")
async def get_export_project_status(project_name: str, job_id: str):
    """Get status of an export operation."""
    return await project_service.get_export_project_job_status(project_name, job_id)


@project_router.post("/export/result")
async def get_export_result(request: ExportResultRequest):
    """Get the result of a completed export job."""
    return await project_service.get_export_result(request.result_url)


# Intent Resource已移除 - 使用sync_list_intents端点替代


# --- Training Resource ---
@project_router.post("/{project_name}/train/{model_label}")
async def start_training(project_name: str, model_label: str):
    """Start model training."""
    config = TrainingConfig(modelLabel=model_label)
    return await training_service.start_training(project_name, config)

@project_router.get("/{project_name}/train")
async def list_training_jobs(project_name: str):
    """List training jobs."""
    return await training_service.list_training_jobs(project_name)

@project_router.get("/{project_name}/train/{job_id}")
async def get_training_status(project_name: str, job_id: str):
    """Get training job status."""
    return await training_service.get_training_status(project_name, job_id)

@project_router.delete("/{project_name}/train/{job_id}")
async def cancel_training(project_name: str, job_id: str):
    """Cancel training job."""
    return await training_service.cancel_training(project_name, job_id)

@project_router.delete("/{project_name}/train/{model_label}")
async def delete_model(project_name: str, model_label: str):
    """Delete a trained model."""
    return await training_service.delete_model(project_name, model_label)

# --- Deployment Resource ---
@project_router.get("/{project_name}/deployments")
async def list_deployments(project_name: str, top: Optional[int] = None, skip: Optional[int] = None):
    """List all deployments for a project."""
    return await deployment_service.list_deployments(project_name, top, skip)

@project_router.post("/{project_name}/deployments/{deployment_name}")
async def deploy_model(
    project_name: str, 
    deployment_name: str, 
    config: DeploymentConfig  
):
    """Deploy a model."""
    return await deployment_service.deploy_model(project_name, deployment_name, config)

@project_router.get("/{project_name}/deployments/{deployment_name}")
async def get_deployment_status(project_name: str, deployment_name: str):
    """Get deployment status."""
    return await deployment_service.get_deployment_status(project_name, deployment_name)

# CLU specific routes
@clu_router.post("/conversation")
async def analyze_conversation(conv_request: ConversationRequest):
    """分析单个会话。"""
    try:
        return await conversation_service.analyze_conversation(conv_request)
        
    except Exception as e:
        raise InvalidRequestBodyError(f"Failed to process request: {str(e)}")


@clu_router.post("/conversation/batch", response_model=BatchConversationResponse)
async def analyze_conversation_batch(batch_request: BatchConversationRequest):
    """批量分析会话。"""
    try:
        return await conversation_service.analyze_conversation_batch(batch_request)
        
    except Exception as e:
        raise InvalidRequestBodyError(f"Failed to process batch request: {str(e)}")


# @clu_router.post("/conversation/default", response_model=BatchConversationResponse)
# async def analyze_conversation_default_targets(default_request: DefaultConversationRequest):
#     """从CosmosDB读取已检查的应用程序列表进行批量会话分析。"""
    
#     try:
#         # 使用ConversationService，封装了完整的CosmosDB目标获取逻辑
#         return await conversation_service.analyze_conversation_with_cosmos_targets(default_request)
        
#     except (InvalidConfigError, DeploymentError):
#         raise
#     except (CosmosDBConnectionError, CosmosDBQueryError, CosmosDBConfigurationError) as e:
#         raise
#     except CosmosDBError as e:
#         raise CLUServiceError(f"CosmosDB operation failed: {str(e)}", status_code=503)
#     except Exception as e:
#         raise InvalidRequestBodyError(f"Failed to process default targets request: {str(e)}")


@clu_router.post("/conversation/default", response_model=BatchConversationResponse)
async def analyze_conversation_from_clu_projects(default_request: DefaultConversationRequest):
    """从CLU项目列表进行批量会话分析，使用缓存优化性能。"""
    
    try:
        # 使用新的analyze_conversation_from_clu方法，从CLU获取项目列表并使用缓存
        return await conversation_service.analyze_conversation_from_clu(default_request)
        
    except (InvalidConfigError, DeploymentError):
        raise
    except Exception as e:
        raise InvalidRequestBodyError(f"Failed to process CLU projects request: {str(e)}")


@clu_router.post("/sync_list_intents", tags=["CLU Operations"])
async def sync_list_intents(query_request: IntentQueryRequest = IntentQueryRequest()):
    """
    同步导出所有默认项目的Intent资产并等待结果，为每个Intent生成UUID5固定ID，支持分页。
    
    该端点会：
    1. 读取DEFAULT_TARGETS配置中的所有项目
    2. 并发调用sync_list_intent处理每个项目
    3. 汇总所有项目的Intent列表
    4. 支持skip和take分页参数
    
    注意：这是长轮询操作，可能需要较长时间。
    """
    from config import settings
    
    if not settings.default_targets:
        raise InvalidConfigError("No default targets configured. Please add `default_targets` to your config.json.")
    
    async def process_single_project(target, index):
        """处理单个项目的辅助函数，复用sync_list_intent逻辑"""
        try:
            # 直接调用sync_list_intent函数，复用其逻辑
            raw_result = await sync_list_intent(target.projectName, query_request)
            
            # raw_result现在是IntentQueryResponse对象
            if isinstance(raw_result, IntentQueryResponse):
                intents_list = raw_result.intents
                intents_count = len(intents_list)
            else:
                # 向后兼容，如果返回的是原始结果
                intents_list = _extract_intents_from_result(raw_result)
                intents_count = len(intents_list)
            
            return {
                "index": index,  # 添加索引以确保排序
                "projectName": target.projectName,
                "deploymentName": target.deploymentName,
                "status": "success",
                "intents": intents_list,
                "intents_count": intents_count,
                "total_count": raw_result.total_count if isinstance(raw_result, IntentQueryResponse) else intents_count,
                "skip": raw_result.skip if isinstance(raw_result, IntentQueryResponse) else query_request.skip,
                "take": raw_result.take if isinstance(raw_result, IntentQueryResponse) else query_request.take,
                "has_more": raw_result.has_more if isinstance(raw_result, IntentQueryResponse) else False,
                "raw_result": raw_result  # 保留原始结果以便调试
            }
            
        except Exception as e:
            return {
                "index": index,  # 添加索引以确保排序
                "projectName": target.projectName,
                "deploymentName": target.deploymentName,
                "status": "error",
                "error": str(e),
                "intents": [],
                "intents_count": 0
            }
    
    # 并发执行所有项目的导出任务，保持DEFAULT_TARGETS的顺序
    tasks = [process_single_project(target, i) for i, target in enumerate(settings.default_targets)]
    raw_results = await asyncio.gather(*tasks, return_exceptions=False)
    
    # 按照原始顺序排序（虽然asyncio.gather通常保持顺序，但这样更明确）
    all_results = sorted(raw_results, key=lambda x: x["index"])
    
    # 移除临时的index字段
    for result in all_results:
        result.pop("index", None)
    
    # 汇总结果
    total_intents = []
    success_count = 0
    error_count = 0
    
    for result in all_results:
        if result["status"] == "success":
            success_count += 1
            total_intents.extend(result["intents"])
        else:
            error_count += 1
    
    return {
        "message": f"Processed {len(settings.default_targets)} projects",
        "success_count": success_count,
        "error_count": error_count,
        "total_intents_count": len(total_intents),
        "skip": query_request.skip,
        "take": query_request.take,
        "projects": all_results,
        "all_intents": total_intents
    }


@clu_router.post("/{project_name}/sync_list_intent", tags=["CLU Operations"], response_model=IntentQueryResponse)
async def sync_list_intent(project_name: str, query_request: IntentQueryRequest = IntentQueryRequest()):
    """
    同步导出指定项目的Intent资产并等待结果，为每个Intent生成UUID5固定ID，支持分页。
    
    该端点会：
    1. 导出指定项目的Intent资产
    2. 为每个Intent基于名称生成UUID5固定ID
    3. 支持skip和take分页参数
    4. 返回包含ID和分页信息的Intent列表
    
    注意：这是长轮询操作，可能需要较长时间。
    """
    import uuid
    
    # 启动导出任务
    export_job_info = await project_service.export_project(project_name, query_request.asset_kind)
    job_id = export_job_info.get("jobId")

    # 轮询等待完成
    timeout, polling_interval, elapsed_time = 300, 2, 0

    while elapsed_time < timeout:
        status_info = await project_service.get_export_project_job_status(project_name, job_id)
        status = status_info.get("status")

        if status == "succeeded":
            result_url = status_info.get("resultUrl")
            raw_result = await project_service.get_export_result(result_url)
            
            # 处理结果，为每个Intent添加UUID5 ID
            processed_result = _process_intents_with_uuid(raw_result)
            
            # 应用分页逻辑
            paginated_result = _apply_pagination_to_intents(
                processed_result, 
                project_name, 
                query_request.skip, 
                query_request.take
            )
            return paginated_result
        
        if status in ["failed", "cancelled"]:
            raise CLUServiceError(f"Export job failed with status: {status}")

        await asyncio.sleep(polling_interval)
        elapsed_time += polling_interval

    raise CLUServiceError("Export job timed out.", status_code=408)


def _process_intents_with_uuid(raw_result):
    """
    处理导出结果，为每个Intent添加UUID5生成的固定ID。
    
    Args:
        raw_result: 从Azure CLU导出的原始结果
        
    Returns:
        处理后的结果，包含UUID ID的Intent列表
    """
    import uuid
    
    if not isinstance(raw_result, dict):
        return raw_result
    
    # 尝试从不同的数据结构中提取intents
    intents_list = []
    
    if "intents" in raw_result:
        intents_list = raw_result["intents"]
    elif "assets" in raw_result and "intents" in raw_result["assets"]:
        intents_list = raw_result["assets"]["intents"]
    else:
        # 尝试找到包含intents的字段
        for key, value in raw_result.items():
            if isinstance(value, list) and len(value) > 0:
                # 检查列表中的第一个元素是否像intent对象
                first_item = value[0]
                if isinstance(first_item, dict) and any(k in first_item for k in ["name", "intent", "intentName", "category"]):
                    intents_list = value
                    break
    
    # 为每个intent添加UUID5 ID
    processed_intents = []
    for intent_item in intents_list:
        if isinstance(intent_item, dict):
            # 创建intent副本
            processed_intent = intent_item.copy()
            
            # 提取intent名称
            intent_name = None
            for name_field in ["name", "intent", "intentName", "category"]:
                if name_field in intent_item:
                    intent_name = intent_item[name_field]
                    break
            
            if intent_name:
                # 使用UUID5生成固定ID
                intent_id = str(uuid.uuid5(uuid.NAMESPACE_DNS, intent_name))
                processed_intent["id"] = intent_id
            
            processed_intents.append(processed_intent)
    
    # 更新结果中的intents
    result_copy = raw_result.copy()
    if "intents" in result_copy:
        result_copy["intents"] = processed_intents
    elif "assets" in result_copy and "intents" in result_copy["assets"]:
        result_copy["assets"]["intents"] = processed_intents
    else:
        # 如果找不到标准结构，直接返回处理后的intents列表
        result_copy = {
            "intents": processed_intents,
            "project_name": raw_result.get("projectName", "unknown"),
            "total_count": len(processed_intents)
        }
    
    return result_copy


def _extract_intents_from_result(processed_result):
    """
    从处理后的结果中提取Intent列表。
    
    Args:
        processed_result: 处理后的导出结果
        
    Returns:
        Intent列表
    """
    if not isinstance(processed_result, dict):
        return []
    
    # 尝试从不同的数据结构中提取intents
    if "intents" in processed_result:
        return processed_result["intents"]
    elif "assets" in processed_result and "intents" in processed_result["assets"]:
        return processed_result["assets"]["intents"]
    else:
        # 尝试找到包含intents的字段
        for key, value in processed_result.items():
            if isinstance(value, list) and len(value) > 0:
                # 检查列表中的第一个元素是否像intent对象
                first_item = value[0]
                if isinstance(first_item, dict) and any(k in first_item for k in ["name", "intent", "intentName", "category", "id"]):
                    return value
    
    return []


def _apply_pagination_to_intents(processed_result, project_name: str, skip: int = 0, take: Optional[int] = None):
    """
    对Intent列表应用分页逻辑。
    
    Args:
        processed_result: 处理后的导出结果
        project_name: 项目名称
        skip: 跳过的记录数
        take: 获取的记录数
        
    Returns:
        IntentQueryResponse: 包含分页信息的响应
    """
    # 提取所有intents
    all_intents = _extract_intents_from_result(processed_result)
    total_count = len(all_intents)
    
    # 应用分页
    start_index = skip
    end_index = start_index + take if take is not None else total_count
    
    # 确保索引不超出范围
    start_index = min(start_index, total_count)
    end_index = min(end_index, total_count)
    
    paginated_intents = all_intents[start_index:end_index]
    
    # 计算是否还有更多数据
    has_more = end_index < total_count
    
    return IntentQueryResponse(
        intents=paginated_intents,
        total_count=total_count,
        skip=skip,
        take=take,
        has_more=has_more,
        project_name=project_name
    )


@clu_router.get("/get_projects", response_model=List[ProjectResponse])
async def list_projects_compat(include_deployment_info: bool = False):
    """
    Get all projects (compatibility route).
    
    Args:
        include_deployment_info: If True, includes the latest deployment info for each project. Defaults to False.
    """
    return await list_projects(include_deployment_info=include_deployment_info)

@clu_router.get("/get_project/{project_name}", response_model=ProjectResponse)
async def get_project_compat(project_name: str):
    """Get project details (compatibility route)."""
    return await get_project(project_name)

@clu_router.get("/get_endpoint")
async def get_endpoint():
    """Get endpoint configuration."""
    return await project_service.get_endpoint()


# --- Utils Operations ---


# --- Logs Operations ---

@logs_router.get("/")
async def list_log_files():
    """
    列出所有可用的日志文件。
    
    返回日志目录中的所有文件，包括文件大小、修改时间等信息。
    为前端开发提供后台日志访问功能。
    """
    try:
        return await logs_service.list_log_files()
    except Exception as e:
        raise CLUServiceError(f"获取日志文件列表失败: {str(e)}", status_code=500)


@logs_router.get("/{filename}")
async def get_log_file_content(
    filename: str,
    lines: Optional[int] = None,
    offset: Optional[int] = None
):
    """
    获取日志文件内容，支持分页查看。
    
    Args:
        filename: 日志文件名
        lines: 限制返回的行数（从offset开始）
        offset: 跳过的行数（用于分页）
    
    Returns:
        日志文件内容和元数据
    """
    try:
        return await logs_service.get_log_file_content(filename, lines, offset)
    except CLUServiceError:
        raise
    except Exception as e:
        raise CLUServiceError(f"获取日志文件内容失败: {str(e)}", status_code=500)

